<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Flux – an open-source tribute to the macOS Drift screensaver</title>
    <meta name="description" content="A cross-platform GPU-based fluid simulation inspired by the Drift screensaver that first appeared in macOS Catalina. Made by @sandy_doo.">
    <meta name="keywords" content="Drift, macOS, windows, screensaver, WebGL, WebGL2, OpenGL, Rust, Elm, WASM, WebAssembly, fluid simulation">
    <meta name="author" content="Sander Melnikov">

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

    <meta property="og:title" content="Flux – an open-source tribute to the macOS Drift screensaver">
    <meta property="og:desciption" content="A cross-platform GPU-based fluid simulation inspired by the Drift screensaver that first appeared in macOS Catalina. Made by @sandy_doo.">
    <meta property="og:url" content="https://flux.sandydoo.me/">
    <meta property="og:image" content="https://assets.sandydoo.me/flux/social-share-2022-07-07.jpg">

    <meta property="twitter:title" content="Flux — an open-source tribute to the macOS Drift screensaver">
    <meta property="twitter:desciption" content="A cross-platform GPU-based fluid simulation inspired by the Drift screensaver that first appeared in macOS Catalina. Made by @sandy_doo.">
    <meta property="twitter:url" content="https://flux.sandydoo.me/">
    <meta property="twitter:creator" content="@sandydoo">
    <meta property="twitter:card" content="summary_large_image">
    <meta property="twitter:image" content="https://assets.sandydoo.me/flux/social-share-2022-07-07.jpg">

    <link rel="preload" href="fonts/Inter-upright.var.woff2" as="font" type="font/woff2" crossorigin="">

    <style>
      :root {
        color-scheme: dark;

        --body-color: #f0ffff;
        --body-secondary-color: #99a2a2;
        --body-sub-color: #272929;

        --breakpoint-sm: 640px;
      }

      @font-face {
        font-family: "Inter var";
        font-weight: 100 900;
        font-display: swap;
        font-style: normal;
        font-named-instance: "Regular";
        src: url("./fonts/Inter-upright.var.woff2") format("woff2");
      }

      html, body {
        margin: 0;
        padding: 0;
        border: 0;
        height: 100%;
        width: 100%;
        background-color: black;
        overflow: hidden;
      }

      body {
        display: flex;
        align-items: center;
        justify-content: center;

        color: var(--body-color);
        font-family: "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
        font-feature-settings: "liga", "dlig", "kern";
        font-size: 1rem;
        line-height: 1.5;
        text-rendering: optimizeLegibility;
        -webkit-font-smoothing: antialiased;
      }

      p, h1, h2, h3, h4, h5, h6, ul, li {
        margin: 0;
        padding: 0;
      }

      .button-group {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        background-color: rgba(20, 20, 20, 0.3);
        border-radius: 0.6em;
        padding: 1em;
      }

      .button-group .button {
        margin: 0.5em 0;
        flex-grow: 1;
      }

      .button {
        border-radius: 0.6em;
        padding: 0.8em 1.5em;
        font-weight: 600;
        text-align: center;
        transition: background-color 0.15s ease-in-out;
      }

      .button.active {
        background-color: rgba(39, 41, 41, 0.5);
      }

      input[type=range] {
        -webkit-appearance: none;
        background: transparent;
        width: 100%;
        height: 3px;
        font-size: 3px;
      }

      input[type=range]::-webkit-slider-runnable-track {
        cursor: col-resize;
        background: #4e4d4d;
        border-radius: 1em;
        height: 1em;
        width: 100%;
        width: 100%;
      }

      input[type=range]::-moz-range-track {
        cursor: col-resize;
        background: #4e4d4d;
        border-radius: 1em;
        height: 1em;
        width: 100%;
        width: 100%;
      }

      input[type=range]::-webkit-slider-thumb {
        -webkit-appearance: none;
        height: 5em;
        width: 5em;
        margin-top: -1.8em;
        border-radius: 5em;
        border: none;
        background: var(--body-color);
        cursor: col-resize;
      }

      input[type=range]::-moz-range-thumb {
        -webkit-appearance: none;
        height: 5em;
        width: 5em;
        border-radius: 5em;
        border: none;
        background: var(--body-color);
        cursor: col-resize;
      }

      button {
        -webkit-appearance: none;
        appearance: none;
        padding: 0;
        margin: 0;
        background: transparent;
        color: inherit;
        border: none;
        text-align: left;
        font-size: inherit;
        font-family: inherit;
        line-height: inherit;
        transition: color 0.15s;
        cursor: pointer;
      }

      button:hover {
        color: var(--body-color);
      }

      .col-span-1 {
        grid-column: span 1;
      }

      .col-span-2 {
        grid-column: span 2;
      }

      .whitespace-nowrap {
        white-space: nowrap;
      }

      .text-secondary {
        color: var(--body-secondary-color);
      }

      a {
        color: inherit;
        transition: color 0.15s;
        text-decoration: none;
      }

      a:hover {
        color: var(--body-color);
      }

      #canvas {
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        width: 100%;
        background-color: black;
      }

      .control-panel {
        display: flex;
        flex-direction: row;

        /* do not touch opacity. it breaks backdrop-filter in chrome/firefox */
        visibility: hidden;
        opacity: 1;
        transition: 0.3s opacity, 0.3s visibility;

        margin-left: 0.3rem;
        margin-right: 0.3rem;
      }

      .active {
        color: var(--body-color);
      }

      .control-container {
        opacity: 0;
        transition: 0.3s opacity;

        margin: 0.3rem auto;
        padding: 4rem 3rem;
        border-radius: 13px;
        border: 1px solid rgb(10, 10, 20);
        background-color: rgba(5, 5, 7, 0.98);
        max-height: calc(100vh - 2 * 4rem - 0.6rem);
        max-width: 660px;
        overflow-y: auto;

        position: relative;
        z-index: 100;
        align-self: flex-start;
      }

      @supports (backdrop-filter: none) {
        .control-container {
          backdrop-filter: blur(12px);
          background-color: rgba(5, 5, 7, 0.7);
        }
      }

      .visible {
        opacity: 1;
        visibility: visible;
      }

      .control-list {
        display: grid;
        grid-template-columns: 1fr;
        gap: 2.6rem;
      }

      .control-list-single {
        display: grid;
        grid-template-columns: 1fr;
        gap: 2.6rem;
      }

      /* workaround for backdrop-filter not working when the parent element has an opacity less than 1 */
      .visible .control-container {
        opacity: 1;
      }

      .control {
        display: flex;
        flex-direction: column;
        width: 100%;
      }

      .control-title {
        font-size: 0.9rem;
        line-height: 1.1;
        letter-spacing: -0.015em;
        grid-column: span 2;
      }

      .control-description {
        font-size: 0.8rem;
        color: var(--body-secondary-color);
        line-height: 1.4;
        letter-spacing: -0.015em;
        margin-top: 0.3rem;
      }

      .control-slider {
        display: flex;
        align-items: center;
        padding: 0.5rem 0;
      }

      .control-value {
        font-size: 0.8rem;
        font-weight: bold;
        letter-spacing: -0.02em;
        font-variant-numeric: tabular-nums;
        width: 2rem;
        text-align: right;
      }

      .gallery {
      }

      .gallery-item {
        margin: 0 10px 10px 0;
        display: inline-flex;
        flex-direction: column;
      }

      .gallery-item:focus-visible {
        outline: none;
      }

      .gallery-item:focus-visible .gallery-icon {
        outline: 2px solid var(--body-color);
        outline-offset: -2px;
      }

      .gallery-icon {
        width: 110px;
        height: 110px;
        border-radius: 8px;
        border: 1px solid var(--body-sub-color);
        background-color: black;
        overflow: hidden;
        transition: outline 0.15s;
      }

      .gallery-icon.active {
        outline: 2px solid var(--body-color);
        outline-offset: -2px;
      }

      footer {
        position: absolute;
        bottom: 24px;
        left: 0;
        z-index: 1;

        display: flex;
        flex-direction: row;

        padding: 0.6rem 0.6rem;
        font-size: 0.65em;
        line-height: 1.3;
        letter-spacing: -0.012em;
        color: var(--body-secondary-color);
      }

      .nav {
        list-style: none;
        display: flex;
        flex-direction: row;
        align-items: baseline;
      }

      .nav li {
        margin-left: 1rem;
      }

      nav li:first {
        margin-left: 0;
      }

      @media (min-width: 640px) {
        .col-span-2-md {
          grid-column: span 2;
        }

        .button-group {
          flex-direction: row;
          align-items: center;
          justify-content: space-evenly;
        }

        .button-group .button {
          margin: 0 0.5em;
        }

        .control-container {
          align-self: center;
        }

        .control-list {
          grid-template-columns: 1fr 1fr;
        }

        footer {
          bottom: 0;
          font-size: 0.75em;
        }
      }

    </style>
  </head>
  <body>
    <canvas id="canvas">Sorry! Flux can’t run in your browser because it doesn’t support WebGL2.</canvas>

    <div id="controls"></div>
  </body>
</html>
